//本hpp用于输出我们日常测试函数的信息，比如一些错误信息，调试信息等\
写入到显示器或文件中，具体看我们想如何实现

#pragma once
#include <ctime>
#include <unistd.h>
#include <pthread.h>
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>
// 日志等级类别
enum Level
{
    Info,    // 正常
    Debug,   // 测试
    Warning, // 警告
    Error    // 错误
};

enum Mode
{
    DisPlay,  // 显示器
    OneFile,  // 一个文件
    ClassFile // 多种类型文件
};

class Log
{
public:
    void LogMessage(int mode, int level, const char *format, ...)
    {
        _level = level;
        _mode = mode;

        // 定义一个缓冲区，用于接收日志信息，最后分模式写入对应的文件
        char rignt[1024];
        // 定义可变参数列表
        va_list args;
        // 初始化可变参数列表,这一步是通过前一个参数的地址将可变参数列表中的各个参数都找到
        va_start(args, format);
        vsnprintf(rignt, sizeof(rignt), format, args);

        //现今buffer中就是日志的内容，但是我们将其组合成理想格式\
        ##level##[time][pid] : message
        std::string left = Get_Left_Message();

        std::string message = left;
        message += " : ";
        message += rignt;
        Print_Mode(message);
    }

private:
    time_t _time;        // 输出日志信息时的当地时间戳
    std::string _matter; // 输出的内容
    int _level;          // 日志等级
    int _mode;           // 输出的模式：显示器或文件输出
    pthread_t _tid;      // 线程tid

    void Print_Mode(std::string &message)
    {
        switch (_mode)
        {
        case DisPlay:
        {
            printf("%s", message.c_str());
        }
        break;
        case OneFile:
        {
            Print_OneFile(message);
        }
        break;
        case ClassFile:
        {
            Print_ClassFile(message);
        }
        break;
        default:
            printf("unknow mode ,error\n");
            break;
        }
    }

    void Print_OneFile(std::string &message)
    {
        //建立统一目录
        std::string dirname = "Log";
        mkdir(dirname.c_str(), 0775);

        umask(0);
        std::string filename = "./Log/log.";
        if (_mode == OneFile)
        {
            filename += "all";
        }
        else
        {
            switch (_level)
            {
            case Info:
                filename += "info";
                break;
            case Debug:
                filename += "debug";
                break;
            case Warning:
                filename += "warning";
                break;
            case Error:
                filename += "error";
                break;
            default:
                filename += "unknow";
                break;
            }
        }
        int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);
        write(fd, message.c_str(), message.size());
        close(fd);
    }

    void Print_ClassFile(std::string &message)
    {
        Print_OneFile(message);
    }

    std::string Get_Left_Message()
    {
        char left_message[1024];
        snprintf(left_message, sizeof(left_message),
                 "[%s][%s][%s]",
                 Get_Level().c_str(),
                 Get_Local_Time().c_str(),
                 Get_Tid().c_str());
        return left_message;
    }

    std::string Get_Local_Time()
    {
        // 先获取时间戳
        _time = time(nullptr);
        // 将时间戳转换为当地时间
        tm *LocalTime = localtime(&_time);
        std::string local_time;

        local_time += std::to_string(LocalTime->tm_year + 1900);
        local_time += '-';

        local_time += std::to_string(LocalTime->tm_mon + 1);
        local_time += '-';

        local_time += std::to_string(LocalTime->tm_mday);
        local_time += ' ';

        local_time += std::to_string(LocalTime->tm_hour);
        local_time += ':';

        local_time += std::to_string(LocalTime->tm_min);
        local_time += ':';

        local_time += std::to_string(LocalTime->tm_sec);
        return local_time;
    }

    std::string Get_Tid()
    {
        return std::to_string((long long)pthread_self());
    }

    std::string Get_Level()
    {
        std::string slevel;
        switch (_level)
        {
        case Info:
            slevel = "Info";
            break;
        case Debug:
            slevel = "Debug";
            break;
        case Warning:
            slevel = "Warning";
            break;
        case Error:
            slevel = "Error";
            break;
        default:
            slevel = "UnKnow";
            break;
        }
        return slevel;
    }
};
Log _log;